package fileTransferController

import (
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

	"gitee.com/ispace/core/infrastructure/common/dto"
	"gitee.com/ispace/core/infrastructure/common/gv"
	"github.com/gin-gonic/gin"

	"github.com/google/uuid"
)

// 文件传输控制器-类
type FileTransferController struct {
	ctx *gin.Context
}

func New(ctx *gin.Context) FileTransferController {
	ic := FileTransferController{}
	ic.ctx = ctx
	return ic
}

// 接口名称：文件传输
// 请求：文件路径
// 响应：文件
func (ic *FileTransferController) File(filePath string) dto.ResultDto[string] {
	// step init:
	var result dto.ResultDto[string]

	// 构建完整路径
	fullPath := filepath.Join(gv.BasePath, filePath)

	// 检查文件是否存在
	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		result.Code = http.StatusNotFound
		result.Success = false
		result.Message = "未找到"
		return result
	}

	// step 5：end
	result.Code = 200
	result.Success = true
	result.Message = "成功"
	result.Data = fullPath
	return result
}

func (ic *FileTransferController) FileUpload(path string, file *multipart.FileHeader) dto.ResultDto[string] {

	// step init:
	result := dto.ResultDto[string]{}

	// step 1: 获取目录
	fullPath := filepath.Join(gv.BasePath, path)

	// 创建目标目录
	dir := filepath.Dir(fullPath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "目录创建失败: " + err.Error()
		return result
	}

	// 保存文件
	if err := ic.ctx.SaveUploadedFile(file, fullPath); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "文件保存失败: " + err.Error()
		return result
	}

	// step 5：end
	result.Code = 200
	result.Success = true
	result.Message = "成功"
	return result
}

type BigFileUploadInitRep struct {
	Key        string `json:"key"`
	ChunkSize  int    `json:"chunkSize"`
	ChunkCount int    `json:"chunkCount"`
}

func (ic *FileTransferController) BigFileUploadInit(size int) dto.ResultDto[BigFileUploadInitRep] {

	// step init:
	result := dto.ResultDto[BigFileUploadInitRep]{}

	// step 1: 生成key
	key := uuid.New().String()

	// step 2: 创建缓存文件夹
	cachePath := filepath.Join(gv.CachePath, key)
	if err := os.MkdirAll(cachePath, 0755); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "缓存文件夹创建失败: " + err.Error()
		return result
	}

	// step 3: 计算分片数量
	chunkCount := size / gv.ChunkSize
	if size%gv.ChunkSize != 0 {
		chunkCount++
	}
	result.Data = BigFileUploadInitRep{
		Key:        key,
		ChunkSize:  gv.ChunkSize,
		ChunkCount: chunkCount,
	}

	result.Code = 200
	result.Success = true
	result.Message = "成功"
	return result
}

func (ic *FileTransferController) BigFileUploadChunk(key string, index int, file *multipart.FileHeader) dto.ResultDto[string] {
	// step init:
	result := dto.ResultDto[string]{}

	// step 1: 获取目录
	cachePath := filepath.Join(gv.CachePath, key, "chunks")

	// 创建目标目录
	if err := os.MkdirAll(cachePath, 0755); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "缓存文件夹创建失败: " + err.Error()
		return result
	}

	// 保存文件
	filePath := filepath.Join(cachePath, fmt.Sprintf("%d", index))
	if err := ic.ctx.SaveUploadedFile(file, filePath); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "文件保存失败: " + err.Error()
		return result
	}

	// step 5：end
	result.Code = 200
	result.Success = true
	result.Message = "成功"
	return result
}

func (ic *FileTransferController) BigFileUploadComplete(key string, name string, size int, chunkSize int, chunkCount int, path string, repeatPolicy int) dto.ResultDto[string] {
	// step init:
	result := dto.ResultDto[string]{}

	// step 1: 获取目录
	cachePath := filepath.Join(gv.CachePath, key, "chunks")

	// step 2: 合并文件
	// 读取所有分片文件，按顺序合并
	files, err := filepath.Glob(filepath.Join(cachePath, "*"))
	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "读取分片文件失败: " + err.Error()
		return result
	}

	// 检查分片数量是否正确
	if len(files) != chunkCount {
		result.Code = http.StatusBadRequest
		result.Success = false
		result.Message = "分片数量不正确"
		return result
	}

	// 创建目标文件
	targetPath := filepath.Join(gv.BasePath, path)
	dir := filepath.Dir(targetPath)

	// 检查并创建父目录
	if err := os.MkdirAll(dir, 0755); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "创建目标目录失败: " + err.Error()
		return result
	}

	targetFile, err := os.Create(targetPath)
	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "创建目标文件失败: " + err.Error()
		return result
	}
	defer targetFile.Close()

	// 按顺序合并分片文件
	for _, file := range files {

		chunkFile, err := os.Open(file)
		if err != nil {
			result.Code = http.StatusInternalServerError
			result.Success = false
			result.Message = "打开分片文件失败: " + err.Error()
			return result
		}
		defer chunkFile.Close()

		if _, err := io.Copy(targetFile, chunkFile); err != nil {
			result.Code = http.StatusInternalServerError
			result.Success = false
			result.Message = "合并分片文件失败: " + err.Error()
			return result
		}
	}

	// 检验总大小
	fileInfo, err := targetFile.Stat()
	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "获取文件信息失败: " + err.Error()
		return result
	}

	if fileInfo.Size() != int64(size) {
		result.Code = http.StatusBadRequest
		result.Success = false
		result.Message = "文件大小不正确"
		return result
	}

	// 删除缓存文件夹
	if err := os.RemoveAll(cachePath); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "删除缓存文件夹失败: " + err.Error()
		return result
	}

	// 返回文件路径
	result.Data = targetPath
	result.Code = 200
	result.Success = true
	result.Message = "成功"
	return result
}

func (ic *FileTransferController) BigFileUploadCancel(key string) dto.ResultDto[string] {
	// step init:
	result := dto.ResultDto[string]{}

	// step 1: 获取目录
	cachePath := filepath.Join(gv.CachePath, key)

	// 删除缓存文件夹
	if err := os.RemoveAll(cachePath); err != nil {
		result.Code = http.StatusInternalServerError
		result.Success = false
		result.Message = "删除缓存文件夹失败: " + err.Error()
		return result
	}

	// step 5：end
	result.Code = 200
	result.Success = true
	result.Message = "成功"
	return result
}
